﻿#include "PluginMgr.h"
#include "boost/filesystem/path.hpp"
#include "boost/filesystem/operations.hpp"
#include <boost/locale.hpp>

static int mirror(unsigned char*buf, int column, int line, DECODE_MIRROR_TYPE type){
	if (type == DECODE_MIRROR_H){
		for (int i = 0; i < line; i++){
			for (int j = 0; j < column / 2; j++){
				std::swap(buf[i * column + j], buf[i * column + (column - j - 1)]);
			}
		}
	} else if (type == DECODE_MIRROR_V){
		for (int i = 0; i < line / 2; i++){
			for (int j = 0; j < column; j++){
				std::swap(buf[i * column + j], buf[(line - i - 1) * column + j]);
			}
		}
	} else{
		return 0;
	}
	return 1;
}
static void transpose(unsigned char*buf, int column, int line)
{
	unsigned char *src = new unsigned char[column * line];
	memcpy(src, buf, column*line);
	for (int i = 0; i < line; i++){
		for (int j = 0; j < column; j++){
			buf[j * line + i] = src[i * column + j];
		}
	}
	delete[] src;
}
static int rotate(unsigned char*buf, int column, int line, DECODE_ROTATE_TYPE type)
{
	if (type == DECODE_ROTATE_LEFT){
		mirror(buf, column, line, DECODE_MIRROR_H);
		transpose(buf, column, line);
	} else if (type == DECODE_ROTATE_RIGHT){
		mirror(buf, column, line, DECODE_MIRROR_V);
		transpose(buf, column, line);
	} else{
		return 0;
	}
	return 1;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

DllDecoderPlugin::~DllDecoderPlugin()
{
}

DllDecoderPlugin::DllDecoderPlugin(const std::wstring& modname)
:DecoderPlugin(), m_plugin(NULL)
{
	_name = L"NA";
	_err = L"NA";
	
	wstring filename = modname;

#if 0
	
	m_hmod = LoadLibrary(filename.c_str());
	if (m_hmod != NULL)
	{
		m_proc = (PluginProc)GetProcAddress(m_hmod, DECODER_PLUGIN_ENTRY_NAME);
		if (m_proc != NULL)
		{
			import();
			if (m_plugin == NULL){
				_err = L"无法实例化插件 " + filename + L" 对象，接口版本不匹配";
			} else{
				_err = L"成功实例化插件" + filename;
			}
		} else{
			_err = L"无法定位插件 " + filename + L" 的入口函数";
		}
	} else{
		DWORD lasterror = GetLastError();
		if (lasterror == 0)
		{
			_err = L"xxx";
		}
		_err = L"无法载入插件 " + filename;
	}

#else
	std::string anSiNam = boost::locale::conv::utf_to_utf<char>(modname);  
	if (m_loader.Open(anSiNam))
	{
		m_proc = (PluginProc)m_loader.GetProc(DECODER_PLUGIN_ENTRY_NAME);
		if (m_proc != NULL)
		{
			import();
			if (m_plugin == NULL)
			{
				_err = wstring(L"无法实例化插件:") + filename + wstring(L" 对象，接口版本不匹配");
			}
			else
			{
				_err = wstring(L"成功实例化插件:") + filename;
			}
		}
		else
		{
			_err = wstring(L"无法定位插件:") + filename + wstring(L" 的入口函数");
		}
	}
	else
	{
		_err = wstring(L"无法载入插件:") + filename + wstring(L",Detail:") + m_loader.WGetLastErrorMsg();
	}

#endif
}

void DllDecoderPlugin::import()
{
	try
	{
		m_plugin = (DecoderPlugin*)m_proc(DECODER_PLUGIN_INTERFACE_VERSION);
	} 
	catch (std::exception)
	{
		_err = wstring(L"插件执行过程中发生SEH异常");
	}
}

bool DllDecoderPlugin::Inited()
{
	return m_plugin != NULL;
}
void DllDecoderPlugin::Close()
{
	m_plugin->Close();
}
/*
*return 0, not rotated,1 rotated
*/
int DllDecoderPlugin::Decode(unsigned char *dest, int dest_buf_len, unsigned char *source, int color_depth, int column, int line, DecodeRequestStruct* args/* = 0*/)
{
	m_plugin->Decode(dest, dest_buf_len, source, color_depth, column, line, args);
	//mirror(dest, column, line, DecoderPluginMgr::getInstance()->GetCurMirrorState());
	//return rotate(dest, column, line, DecoderPluginMgr::getInstance()->GetCurRotateState());
	return 0;
}
void DllDecoderPlugin::GetDecodedParam(DecodedParam orig_param, int &new_color_depth, int &new_column, int &new_line, DecodeRequestStruct* args/* = 0*/)
{
	m_plugin->GetDecodedParam(orig_param, new_color_depth, new_column, new_line, args);
}
const wchar_t* DllDecoderPlugin::Name()
{
	//must ensure the return not NULL
	if (m_plugin->Name() == NULL){
		return _name.c_str();
	}
	return m_plugin->Name();
}
const wchar_t* DllDecoderPlugin::ErrorInfo()
{
	if (m_plugin->ErrorInfo() == NULL)
		return _err.c_str();
	return m_plugin->ErrorInfo();
}

bool DllDecoderPlugin::SetLsb(int lsb)
{
	return m_plugin->SetLsb(lsb);
}
int DllDecoderPlugin::GetLsb()
{
	return m_plugin->GetLsb();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
DecoderPluginMgr::DecoderPluginMgr()
{
	decoders.clear();
	
#ifdef _WIN32
	RescanPlugins("\\Decoders\\", decoders);
	RescanPlugins("\\ReadFormats\\", read_formats);
#else	RescanPlugins("/Decoders", decoders);
	RescanPlugins("/ReadFormats", read_formats);
				  
#endif // _WIN32
	SetDefaultDecoder();
	
}

DecoderPluginMgr::~DecoderPluginMgr()
{
	for (std::map<wstring, DecoderPlugin*>::iterator it = decoders.begin(); it != decoders.end(); it++){
		it->second->Close();
		delete it->second;
	}
}

void DecoderPluginMgr::SetDefaultDecoder()
{
	bool find_default_decoder = false;
	bool find_default_read_format = false;
	for (std::map<wstring, DecoderPlugin*>::iterator it = decoders.begin(); it != decoders.end(); it++){
		if (it->first == L"Linear"){
			default_decoder = it->first;
			find_default_decoder = true;
			break;
		}
	}
	if (decoders.size() > 0 && !find_default_decoder) {
		default_decoder = decoders.begin()->first;
	}

	for (std::map<wstring, DecoderPlugin*>::iterator it = read_formats.begin(); it != read_formats.end(); it++) {
		if (it->first == L"Default") {
			default_read_format = it->first;
			find_default_read_format = true;
			break;
		}
	}
	if (read_formats.size() > 0 && !find_default_read_format) {
		default_read_format = read_formats.begin()->first;
	}
	return;
}
int DecoderPluginMgr::RescanPlugins(string path, std::map<wstring, DecoderPlugin*> &plugin_map)
{
	string fullpath = "";
	
	try
	{
		fullpath =  boost::filesystem::initial_path<boost::filesystem::path>().string();
	}
	catch (...)
	{
		cout << "boost::filesystem::initial_path catch except " << endl;
		fullpath = ".";
	}
	
	fullpath += path;
	cout << "[pluginmgr] Decoder plugin path = " << fullpath << endl;
	boost::filesystem::path full_path(fullpath/*, boost::filesystem::native*/);
	if (boost::filesystem::exists(full_path))
	{
		 for (boost::filesystem::directory_iterator item_begin(full_path); item_begin != boost::filesystem::directory_iterator(); item_begin++){
			if (boost::filesystem::is_regular_file(*item_begin))
			{
				std::wstring file_name = item_begin->path().wstring();
				if (file_name.find(DLL_SUFFIX) != std::string::npos)
				{
					wcout << "[pluginFileName] "  << file_name << endl;
					DllDecoderPlugin *decoder = new DllDecoderPlugin(file_name);
					if (decoder && decoder->Inited()) 
					{
						plugin_map[decoder->Name()] = decoder;
						wcout << "[pluginLoadName] " << decoder->Name() << endl;
					} 
					else 
					{
						delete decoder;
					}
				}
			}
		}
	}
	return plugin_map.size();
}